package service

import (
	"context"
	"github.com/robfig/cron/v3"
	"time"
	"webook/internal/domain"
	"webook/internal/repository"
)

// JobService 通用的任务调度服务
type JobService interface {
	// Preempt 抢占任务
	Preempt(ctx context.Context) (domain.Job, error)
	ResetNextTime(ctx context.Context, job domain.Job) error
}

type CronJobService struct {
	repo repository.JobRepository
}

func NewCronJobService(repo repository.JobRepository) JobService {
	return &CronJobService{
		repo: repo,
	}
}

func (svc *CronJobService) ResetNextTime(ctx context.Context, job domain.Job) error {
	parser := cron.NewParser(cron.Second | cron.Minute | cron.Hour |
		cron.Dom | cron.Month | cron.Dow | cron.Descriptor)
	parse, _ := parser.Parse(job.Expr)
	nextTime := parse.Next(time.Now()).UnixMilli()
	return svc.repo.UpdateNextTime(ctx, job.Id, nextTime)
}

func (svc *CronJobService) Preempt(ctx context.Context) (domain.Job, error) {
	// 抢占任务
	job, err := svc.repo.Preempt(ctx)
	if err != nil {
		return domain.Job{}, err
	}
	// 考虑续期问题
	done := make(chan struct{})
	ticker := time.NewTicker(time.Second * 30)
	go func() {
		for {
			select {
			case <-ticker.C:
				// 去续期
				svc.refresh(job.Id)
			case <-done:
				// 不用继续续期
				return
			}
		}
	}()
	// 难道就一直占用着吗？你需要提供一个释放任务的方法
	job.CancelFunc = func() error {
		ticker.Stop()
		// 触发协程关闭
		close(done)
		// 调用Release逻辑
		releaseCtx, cancel := context.WithTimeout(context.Background(), time.Second*30)
		defer cancel()
		return svc.repo.Release(releaseCtx, job.Id)
	}
	return job, err
}

func (svc *CronJobService) refresh(jobId int64) {
	// 这个方法其实就是不断刷新更新时间即可
	ctx, cancel := context.WithTimeout(context.Background(), time.Second*30)
	defer cancel()
	err := svc.repo.UpdateUtime(ctx, jobId)
	if err != nil {
		// TODO: 记录日志，续期失败
	}
}
